package com.kexilo.core.common.config;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 链路追踪配置
 * 提供分布式追踪和性能监控功能
 * 
 * @author Kexilo
 */
@Configuration
@ConditionalOnProperty(prefix = "spring.features", name = "tracing-enabled", havingValue = "true", matchIfMissing = true)
public class TracingConfiguration {
    
    private static final Logger log = LoggerFactory.getLogger(TracingConfiguration.class);
    
    @Value("${spring.application.name:kexilo-system}")
    private String applicationName;
    
    /**
     * 链路追踪过滤器
     */
    @Bean
    public TracingFilter tracingFilter() {
        return new TracingFilter();
    }
    
    /**
     * 度量注册表自定义器
     */
    @Bean
    public MeterRegistryCustomizer<MeterRegistry> meterRegistryCustomizer() {
        return registry -> {
            registry.config().commonTags(
                "application", applicationName,
                "version", "1.0.0",
                "environment", getEnvironment()
            );
        };
    }
    
    /**
     * 简单度量注册表（用于开发环境）
     */
    @Bean
    public MeterRegistry meterRegistry() {
        return new SimpleMeterRegistry();
    }
    
    /**
     * 链路追踪过滤器实现
     */
    public static class TracingFilter extends OncePerRequestFilter {
        
        private static final Logger log = LoggerFactory.getLogger(TracingFilter.class);
        private static final String TRACE_ID_HEADER = "X-Trace-Id";
        private static final String SPAN_ID_HEADER = "X-Span-Id";
        
        @Override
        protected void doFilterInternal(HttpServletRequest request, 
                                       HttpServletResponse response, 
                                       FilterChain filterChain) throws ServletException, IOException {
            
            String traceId = getOrGenerateTraceId(request);
            String spanId = generateSpanId();
            
            // 设置追踪上下文
            TraceContext.setTraceId(traceId);
            TraceContext.setSpanId(spanId);
            
            // 设置响应头
            response.setHeader(TRACE_ID_HEADER, traceId);
            response.setHeader(SPAN_ID_HEADER, spanId);
            
            long startTime = System.currentTimeMillis();
            String requestURI = request.getRequestURI();
            String method = request.getMethod();
            
            try {
                log.info("开始处理请求 - TraceId: {}, SpanId: {}, Method: {}, URI: {}", 
                        traceId, spanId, method, requestURI);
                
                filterChain.doFilter(request, response);
                
                long duration = System.currentTimeMillis() - startTime;
                int status = response.getStatus();
                
                log.info("完成处理请求 - TraceId: {}, SpanId: {}, Method: {}, URI: {}, Status: {}, Duration: {}ms", 
                        traceId, spanId, method, requestURI, status, duration);
                
                // 记录度量数据
                recordMetrics(method, requestURI, status, duration);
                
            } catch (Exception e) {
                long duration = System.currentTimeMillis() - startTime;
                
                log.error("处理请求异常 - TraceId: {}, SpanId: {}, Method: {}, URI: {}, Duration: {}ms", 
                         traceId, spanId, method, requestURI, duration, e);
                
                // 记录异常度量
                recordErrorMetrics(method, requestURI, duration, e);
                throw e;
                
            } finally {
                // 清理追踪上下文
                TraceContext.clear();
            }
        }
        
        /**
         * 获取或生成追踪ID
         */
        private String getOrGenerateTraceId(HttpServletRequest request) {
            String traceId = request.getHeader(TRACE_ID_HEADER);
            if (traceId == null || traceId.trim().isEmpty()) {
                traceId = generateTraceId();
            }
            return traceId;
        }
        
        /**
         * 生成追踪ID
         */
        private String generateTraceId() {
            return UUID.randomUUID().toString().replace("-", "");
        }
        
        /**
         * 生成Span ID
         */
        private String generateSpanId() {
            return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
        }
        
        /**
         * 记录度量数据
         */
        private void recordMetrics(String method, String uri, int status, long duration) {
            // 这里应该使用实际的MeterRegistry记录度量
            // 简化实现，只记录日志
            log.debug("记录度量数据 - Method: {}, URI: {}, Status: {}, Duration: {}ms", 
                     method, uri, status, duration);
        }
        
        /**
         * 记录异常度量
         */
        private void recordErrorMetrics(String method, String uri, long duration, Exception e) {
            log.debug("记录异常度量 - Method: {}, URI: {}, Duration: {}ms, Error: {}", 
                     method, uri, duration, e.getClass().getSimpleName());
        }
    }
    
    /**
     * 追踪上下文
     */
    public static class TraceContext {
        private static final ThreadLocal<String> TRACE_ID = new ThreadLocal<>();
        private static final ThreadLocal<String> SPAN_ID = new ThreadLocal<>();
        
        public static void setTraceId(String traceId) {
            TRACE_ID.set(traceId);
        }
        
        public static String getTraceId() {
            return TRACE_ID.get();
        }
        
        public static void setSpanId(String spanId) {
            SPAN_ID.set(spanId);
        }
        
        public static String getSpanId() {
            return SPAN_ID.get();
        }
        
        public static void clear() {
            TRACE_ID.remove();
            SPAN_ID.remove();
        }
        
        public static String getFullTraceInfo() {
            return String.format("TraceId: %s, SpanId: %s", getTraceId(), getSpanId());
        }
    }
    
    /**
     * 获取当前环境
     */
    private String getEnvironment() {
        String profile = System.getProperty("spring.profiles.active");
        return profile != null ? profile : "default";
    }
}
